package service

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gitee.com/fu-ce-wei/pi-mapper/dto"
	"gitee.com/fu-ce-wei/pi-mapper/internal/config"
	"gitee.com/fu-ce-wei/pi-mapper/pkg/logger"
	"gitee.com/fu-ce-wei/pi-mapper/pkg/redis"
	"go.uber.org/zap"
)

// VideoService 视频服务接口
type VideoService interface {
	// GetVideoList 获取视频列表
	GetVideoList(ctx context.Context, count int) (*dto.VideoListResponse, error)

	// GetVideoURL 获取视频完整URL
	GetVideoURL(filename string) string

	// ValidateVideoFile 验证视频文件
	ValidateVideoFile(filename string) bool

	// GetVideoInfo 获取视频信息
	GetVideoInfo(ctx context.Context, filename string) (*dto.VideoResponse, error)
}

// videoServiceImpl 视频服务实现
type videoServiceImpl struct {
	redisClient *redis.Client
	config      *config.Config
	logger      *logger.Logger
}

// NewVideoService 创建视频服务实例
func NewVideoService(redisClient *redis.Client, config *config.Config, logger *logger.Logger) VideoService {
	return &videoServiceImpl{
		redisClient: redisClient,
		config:      config,
		logger:      logger,
	}
}

// GetVideoList 获取视频列表
func (s *videoServiceImpl) GetVideoList(ctx context.Context, count int) (*dto.VideoListResponse, error) {
	if count <= 0 {
		count = 5
	}
	if count > 20 {
		count = 20
	}

	// 记录请求日志
	s.logger.Info("开始获取视频列表",
		zap.Int("requested_count", count),
		zap.String("redis_key", s.config.Video.RedisKey),
	)

	// 从Redis获取随机视频
	filenames, err := s.redisClient.GetRandomVideos(ctx, s.config.Video.RedisKey, count)
	if err != nil {
		s.logger.Error("获取随机视频失败",
			zap.Error(err),
			zap.String("redis_key", s.config.Video.RedisKey),
		)
		return nil, fmt.Errorf("获取视频列表失败: %w", err)
	}

	// 如果没有找到视频
	if len(filenames) == 0 {
		s.logger.Warn("没有找到视频文件",
			zap.String("redis_key", s.config.Video.RedisKey),
		)
		return &dto.VideoListResponse{
			Videos: []dto.VideoResponse{},
			URLs:   []string{},
			Total:  0,
			Count:  0,
		}, nil
	}

	// 构建响应
	videos := make([]dto.VideoResponse, 0, len(filenames))
	urls := make([]string, 0, len(filenames))

	for _, filename := range filenames {
		// 验证文件名
		if !s.ValidateVideoFile(filename) {
			s.logger.Warn("跳过无效的视频文件名",
				zap.String("filename", filename),
			)
			continue
		}

		// 获取视频URL
		videoURL := s.GetVideoURL(filename)

		// 构建视频响应
		video := dto.VideoResponse{
			Name: filename,
			URL:  videoURL,
		}

		// 尝试获取文件信息
		if info, err := s.GetVideoInfo(ctx, filename); err == nil {
			video.Size = info.Size
			video.CreatedAt = info.CreatedAt
		}

		videos = append(videos, video)
		urls = append(urls, videoURL)
	}

	// 获取总数
	total, err := s.redisClient.GetVideoCount(ctx, s.config.Video.RedisKey)
	if err != nil {
		s.logger.Error("获取视频总数失败",
			zap.Error(err),
			zap.String("redis_key", s.config.Video.RedisKey),
		)
		// 不返回错误，使用0作为总数
		total = 0
	}

	response := &dto.VideoListResponse{
		Videos: videos,
		URLs:   urls,
		Total:  int(total),
		Count:  len(videos),
	}

	s.logger.Info("成功获取视频列表",
		zap.Int("returned_count", len(videos)),
		zap.Int64("total_count", total),
	)

	return response, nil
}

// GetVideoURL 获取视频完整URL
func (s *videoServiceImpl) GetVideoURL(filename string) string {
	// 不再清理文件名，因为现在文件名包含路径前缀
	// 直接拼接URL
	return fmt.Sprintf("%s/%s", strings.TrimRight(s.config.Video.BaseURL, "/"), filename)
}

// ValidateVideoFile 验证视频文件
func (s *videoServiceImpl) ValidateVideoFile(filename string) bool {
	if filename == "" {
		return false
	}

	// 检查文件扩展名
	ext := strings.ToLower(filepath.Ext(filename))
	validExtensions := s.config.Scanner.FileExtensions

	for _, validExt := range validExtensions {
		if ext == strings.ToLower(validExt) {
			return true
		}
	}

	return false
}

// GetVideoInfo 获取视频信息
func (s *videoServiceImpl) GetVideoInfo(ctx context.Context, filename string) (*dto.VideoResponse, error) {
	if !s.ValidateVideoFile(filename) {
		return nil, fmt.Errorf("无效的视频文件名: %s", filename)
	}

	// 解析文件名中的路径前缀（如"VideoDownUP1"）
	parts := strings.SplitN(filename, string(filepath.Separator), 2)
	if len(parts) < 2 {
		return nil, fmt.Errorf("文件名格式错误，缺少路径前缀: %s", filename)
	}

	pathPrefix := parts[0]
	relativePath := parts[1]

	// 根据路径前缀找到对应的根路径
	var rootPath string
	found := false
	for _, rp := range s.config.Scanner.RootPaths {
		if filepath.Base(rp) == pathPrefix {
			rootPath = rp
			found = true
			break
		}
	}

	if !found {
		return nil, fmt.Errorf("未找到对应的根路径: %s", pathPrefix)
	}

	// 构建完整的文件路径
	filePath := filepath.Join(rootPath, relativePath)

	// 检查文件是否存在
	info, err := getFileInfo(filePath)
	if err != nil {
		s.logger.Error("获取文件信息失败",
			zap.String("filename", filename),
			zap.String("path", filePath),
			zap.Error(err),
		)
		return nil, fmt.Errorf("获取文件信息失败: %w", err)
	}

	return &dto.VideoResponse{
		Name:      filename,
		URL:       s.GetVideoURL(filename),
		Size:      info.Size,
		CreatedAt: info.ModTime,
	}, nil
}

// getFileInfo 获取文件信息（内部函数）
func getFileInfo(filePath string) (*fileInfo, error) {
	info, err := os.Stat(filePath)
	if err != nil {
		return nil, err
	}

	return &fileInfo{
		Size:    info.Size(),
		ModTime: info.ModTime(),
		IsDir:   info.IsDir(),
	}, nil
}

// fileInfo 文件信息结构
type fileInfo struct {
	Size    int64
	ModTime time.Time
	IsDir   bool
}

// VideoStats 视频统计信息
type VideoStats struct {
	TotalVideos int64
	TotalSize   int64
	LastUpdated time.Time
	OldestVideo string
	NewestVideo string
}

// GetVideoStats 获取视频统计信息
func (s *videoServiceImpl) GetVideoStats(ctx context.Context) (*VideoStats, error) {
	// 获取视频总数
	total, err := s.redisClient.GetVideoCount(ctx, s.config.Video.RedisKey)
	if err != nil {
		return nil, fmt.Errorf("获取视频总数失败: %w", err)
	}

	// TODO: 可以实现更详细的统计信息
	return &VideoStats{
		TotalVideos: total,
		LastUpdated: time.Now(),
	}, nil
}

// RefreshVideoCache 刷新视频缓存
func (s *videoServiceImpl) RefreshVideoCache(ctx context.Context) error {
	// 清除Redis缓存
	err := s.redisClient.ClearVideos(ctx, s.config.Video.RedisKey)
	if err != nil {
		return fmt.Errorf("清除缓存失败: %w", err)
	}

	s.logger.Info("视频缓存已刷新",
		zap.String("redis_key", s.config.Video.RedisKey),
	)

	return nil
}

// AddVideoToCache 手动添加视频到缓存
func (s *videoServiceImpl) AddVideoToCache(ctx context.Context, filename string) error {
	if !s.ValidateVideoFile(filename) {
		return fmt.Errorf("无效的视频文件名: %s", filename)
	}

	err := s.redisClient.AddVideo(ctx, s.config.Video.RedisKey, filename)
	if err != nil {
		return fmt.Errorf("添加视频到缓存失败: %w", err)
	}

	s.logger.Info("视频已添加到缓存",
		zap.String("filename", filename),
		zap.String("redis_key", s.config.Video.RedisKey),
	)

	return nil
}

// RemoveVideoFromCache 从缓存中移除视频
func (s *videoServiceImpl) RemoveVideoFromCache(ctx context.Context, filename string) error {
	err := s.redisClient.RemoveVideo(ctx, s.config.Video.RedisKey, filename)
	if err != nil {
		return fmt.Errorf("从缓存中移除视频失败: %w", err)
	}

	s.logger.Info("视频已从缓存中移除",
		zap.String("filename", filename),
		zap.String("redis_key", s.config.Video.RedisKey),
	)

	return nil
}
